package com.itheima.es.controller;

import com.itheima.es.pojo.People;
import com.itheima.es.repository.PeopleRepository;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.InternalAvg;
import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * @Author Administrator
 * @Date 2021/11/19:19:55
 * @Description:
 */
@RestController
public class PeopleController {

    @Autowired
    private PeopleRepository peopleRepository;

    @GetMapping("add")
    public People add() {
        People people = new People();
        people.setId(1L);
        people.setName("ccm");
        people.setAddress("北京市昌平区");
        people.setAge(30);
        return peopleRepository.save(people);
    }

    @GetMapping("query")
    public List<People> query() {
        return peopleRepository.findByNameAndAgeBetween("ccm", 19, 30);
    }

    @GetMapping("adds")
    public Iterable<People> adds() {

        People p1 = new People(2L, "ccm2", "北京市昌平区2", 32);
        People p2 = new People(3L, "ccm3", "北京市昌平区3", 33);
        People p3 = new People(4L, "ccm4", "北京市昌平区4", 34);

        return peopleRepository.saveAll(Arrays.asList(p1, p2, p3));
    }

    @GetMapping("q1")
    public Iterable<People> q1() {
        BoolQueryBuilder must = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("name", "ccm"));
        return peopleRepository.search(must);
    }

    @GetMapping("q2")
    public Page<People> q2(){
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 添加基本的分词查询
        queryBuilder.withQuery(QueryBuilders.matchQuery("name", "ccm2"));
        queryBuilder.withFields("name", "id", "age");
        // 初始化分页参数
        int page = 0;
        int size = 3;
        // 设置分页参数
        queryBuilder.withPageable(PageRequest.of(page, size));

        // 排序
        queryBuilder.withSort(SortBuilders.fieldSort("age").order(SortOrder.DESC));

        // 执行搜索，获取结果
        Page<People> items = this.peopleRepository.search(queryBuilder.build());
        // 打印总条数
        System.out.println(items.getTotalElements());
        // 打印总页数
        System.out.println(items.getTotalPages());
        // 每页大小
        System.out.println(items.getSize());
        // 当前页
        System.out.println(items.getNumber());
        items.forEach(System.out::println);

        return items;
    }

    @GetMapping("q3")
    public Aggregation q3(){
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 不查询任何结果
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
        // 1、添加一个新的聚合，聚合类型为terms，聚合名称为brands，聚合字段为brand
        queryBuilder.addAggregation(
                AggregationBuilders.terms("age_group").field("age"));
        // 2、查询,需要把结果强转为AggregatedPage类型
        AggregatedPage<People> aggPage = (AggregatedPage<People>) this.peopleRepository.search(queryBuilder.build());
        // 3、解析
        // 3.1、从结果中取出名为brands的那个聚合，
        // 因为是利用String类型字段来进行的term聚合，所以结果要强转为StringTerm类型
        ParsedLongTerms agg = (ParsedLongTerms) aggPage.getAggregation("age_group");
        // 3.2、获取桶
        List<ParsedLongTerms.ParsedBucket> buckets = (List<ParsedLongTerms.ParsedBucket>) agg.getBuckets();
        // 3.3、遍历
        for (ParsedLongTerms.ParsedBucket bucket : buckets) {
            // 3.4、获取桶中的key，即品牌名称
            System.out.println(bucket.getKeyAsString());
            // 3.5、获取桶中的文档数量
            System.out.println(bucket.getDocCount());
        }
        return agg;
    }

    @GetMapping("q4")
    public AggregatedPage<People> q4(){
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 不查询任何结果
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
        // 1、添加一个新的聚合，聚合类型为terms，聚合名称为brands，聚合字段为brand
        queryBuilder.addAggregation(
                AggregationBuilders.terms("name_group").field("name")
                        .subAggregation(AggregationBuilders.avg("ageAvg").field("age")) // 在品牌聚合桶内进行嵌套聚合，求平均值
        );
        // 2、查询,需要把结果强转为AggregatedPage类型
        AggregatedPage<People> aggPage = (AggregatedPage<People>) this.peopleRepository.search(queryBuilder.build());
        // 3、解析
        // 3.1、从结果中取出名为brands的那个聚合，
        // 因为是利用String类型字段来进行的term聚合，所以结果要强转为StringTerm类型
        ParsedStringTerms agg = (ParsedStringTerms) aggPage.getAggregation("name_group");
        // 3.2、获取桶
        List<ParsedStringTerms.ParsedBucket> buckets = (List<ParsedStringTerms.ParsedBucket>) agg.getBuckets();
        // 3.3、遍历
        for (ParsedStringTerms.ParsedBucket bucket : buckets) {
            // 3.4、获取桶中的key，即品牌名称  3.5、获取桶中的文档数量
            System.out.println(bucket.getKeyAsString() + "，共" + bucket.getDocCount() + "台");

            // 3.6.获取子聚合结果：
            ParsedAvg avg = (ParsedAvg) bucket.getAggregations().asMap().get("ageAvg");
            System.out.println("平均售价：" + avg.getValue());
        }
        return null;
    }
}
